// $Id: expression.c 28 2015-03-11 01:53:12Z robim.poa@gmail.com $
//-----------------------------------------------------------------------------
// Purpose: Interpretation of code expressions.
// $Rev: 28 $
// $Author: robim.poa@gmail.com $
// $Date: 2015-03-11 01:53:12 +0000 (Wed, 11 Mar 2015) $

#include <stdlib.h>
#include <stdio.h>

#include "debug.h"
#include "expression.h"
#include "ast.h"
#include "text_decoding.h"
#include "text_processing.h"

void PrintExpressionArray(struct tp_node_expression *node_expression_head)
{
	printf("      Type  Data\n");
	printf("Node:  %d     %d\n",node_expression_head->type,node_expression_head->data);
	while(node_expression_head->next != NULL)
	{
		node_expression_head = node_expression_head->next;
		printf("Node:  %d     %d\n",node_expression_head->type, node_expression_head->data);
	}
}

struct node_ast* BuildExpressionTree(struct tp_node_expression *node_expression_head)
{
	int operator = OPERATOR_NONE;
	struct tp_node_expression *node_expression_aux2, *node_expression_aux1;
	int parentheses_removed;

	do
	{
		parentheses_removed = 0;

		if(operator == OPERATOR_NONE) operator = ExpressionSplit(node_expression_head, &node_expression_aux1, ARITHMETIC_HIERARCHY_LOGIC);
		if(operator == OPERATOR_NONE) operator = ExpressionSplit(node_expression_head, &node_expression_aux1, ARITHMETIC_HIERARCHY_COMPARE);
		if(operator == OPERATOR_NONE) operator = ExpressionSplit(node_expression_head, &node_expression_aux1, ARITHMETIC_HIERARCHY_TERM);
		if(operator == OPERATOR_NONE) operator = ExpressionSplit(node_expression_head, &node_expression_aux1, ARITHMETIC_HIERARCHY_COEFFICIENT);
		if(operator == OPERATOR_NONE) operator = ExpressionSplit(node_expression_head, &node_expression_aux1, ARITHMETIC_HIERARCHY_FACTOR);
		
		if(operator == OPERATOR_NONE) parentheses_removed = RemoveParentheses(&node_expression_head);
	}while(parentheses_removed);



	if(operator != OPERATOR_NONE)
	{
		struct node_ast *node_ast = astCreateNode(operator,0);
		struct node_ast *node_ast_aux;
		node_ast->left = BuildExpressionTree(node_expression_head);
		node_ast->right = BuildExpressionTree(node_expression_aux1);
		
		node_ast_aux = node_ast->left;
		
		node_ast_aux = node_ast->right;
		return node_ast;
	}
	else
	{
		switch(node_expression_head->type)
		{
			case EXPRESSION_TYPE_VALUE:
				return astCreateNode(AST_VALUE, node_expression_head->data);

			case EXPRESSION_TYPE_VAR:
				return astCreateNode(AST_VAR, node_expression_head->data);
				
			default:
				printf("Critical error: montagem da arvore (não é value nem var)\n");
				return NULL;
		}
	}
}

int ExpressionSplit(struct tp_node_expression *node_expression_head1, struct tp_node_expression **node_expression_head2, int arithmetic_hierarchy)
{
	int operator = OPERATOR_NONE;
	int parentheses = 0;
	struct tp_node_expression *node_expression_aux2, *node_expression_aux1;

	node_expression_aux1 = node_expression_head1;
	while(node_expression_aux1->next != NULL)
	{
		if((node_expression_aux1->type == EXPRESSION_TYPE_OPERATOR) && (node_expression_aux1->data == BRACKETS_PARENTHESES_OPEN))
			parentheses++;
		else if((node_expression_aux1->type == EXPRESSION_TYPE_OPERATOR) && (node_expression_aux1->data == BRACKETS_PARENTHESES_CLOSE))
			parentheses--;
		else if((node_expression_aux1->type == EXPRESSION_TYPE_OPERATOR) && HierarchyCompare(arithmetic_hierarchy, node_expression_aux1->data)  && parentheses==0)
		{
			node_expression_aux2->next = NULL;
			operator = astOperatorToFunc(node_expression_aux1->data);
			node_expression_aux1 = node_expression_aux1->next;
			break;
		}
		node_expression_aux2 = node_expression_aux1;
		node_expression_aux1 = node_expression_aux1->next;
	}

	*node_expression_head2 = node_expression_aux1;
	return operator;
}

int HierarchyCompare(int arithmetic_hierarchy, int operator)
{
	switch(arithmetic_hierarchy)
	{
		case ARITHMETIC_HIERARCHY_LOGIC:
			switch(operator)
			{
				case LOGIC_OPERATOR_OR:
				case LOGIC_OPERATOR_AND:
				case LOGIC_OPERATOR_NOT:
					return 1;
			}
			break;

		case ARITHMETIC_HIERARCHY_COMPARE:
			switch(operator)
			{
				case COMPARISON_OPERATOR_EQUAL:
				case COMPARISON_OPERATOR_NEQUAL:
				case COMPARISON_OPERATOR_GREATER:
				case COMPARISON_OPERATOR_LESS:
				case COMPARISON_OPERATOR_GREATER_EQUAL:
				case COMPARISON_OPERATOR_LESS_EQUAL:
				case ARITHMETIC_OPERATOR_EQUAL:
					return 1;
			}
			break;
		
		case ARITHMETIC_HIERARCHY_TERM:
			switch(operator)
			{
				case ARITHMETIC_OPERATOR_PLUS:
				case ARITHMETIC_OPERATOR_MINUS:
					return 1;
			}
			break;

		case ARITHMETIC_HIERARCHY_COEFFICIENT:
			switch(operator)
			{
				case ARITHMETIC_OPERATOR_MULTI:
				case ARITHMETIC_OPERATOR_DIVIS:
					return 1;
			}
			break;

		case ARITHMETIC_HIERARCHY_FACTOR:
			switch(operator)
			{
				case ARITHMETIC_OPERATOR_POWER:
				case ARITHMETIC_OPERATOR_MODULO:
					return 1;
			}
			break;
			
		default:
			printf("Critial error: HierarchyCompare\n");
	}

	return 0;
}

int RemoveParentheses(struct tp_node_expression **node_expression_head)
{
	struct tp_node_expression *node_expression_aux1, *node_expression_aux2 ;
	node_expression_aux1 = *node_expression_head;

	if((node_expression_aux1->type == EXPRESSION_TYPE_OPERATOR) && (node_expression_aux1->data == BRACKETS_PARENTHESES_OPEN))
	{
		while(node_expression_aux1->next != NULL)
		{
			node_expression_aux2 = node_expression_aux1;
			node_expression_aux1 = node_expression_aux1->next;
		}

		if((node_expression_aux1->type == EXPRESSION_TYPE_OPERATOR) && (node_expression_aux1->data == BRACKETS_PARENTHESES_CLOSE))
		{
			//Remove parentheses
			node_expression_aux2->next = NULL;
			node_expression_aux1 = *node_expression_head;
			*node_expression_head = node_expression_aux1->next;
			return 1;
		}
	}
	return 0;
}